package de.fuberlin.inf.alp2;
import de.fuberlin.inf.alp2.utils.*;

/**
 * This class has been implemented within the scope of the third exercise of
 * the lecture <i>"Algorithmen und Programmierung 2 - Objektorientierte
 * Programmierung"</i>.
 * @author stefanr
 */
public class ToBinary {

	/**
	 * @param args (If first argument contains an double, it will be used as
	 * decimal value. Otherwise the program will ask you to enter it.
	 */
	public static void main(String[] args) {
		final double DECIMAL;
		boolean[] binary;

		DECIMAL = ToBinary.getDecimalValue(args);
		binary = ToBinary.toBinary(DECIMAL);
		System.out.print("binary:   ");
		for (int i = 0; i < 52; i++)
			System.out.print(((binary[i]) ? "1" : "0"));
		System.out.println("\ndecimal:  " + ToBinary.fromBinary(binary));
		System.out.print("original: " + DECIMAL);

	}

	/**
	 * This method will use the first parameter to convert it to double. If this
	 * is not possible, it requests an input by the user, until the entered
	 * string has been successfully converted to double.
	 * @param args If first argument contains a double, it will be used as
	 * decimal. Otherwise the program will ask to type in the value again.
	 * @return The double value of the passed string.
	 */
	private static double getDecimalValue(String[] args) {
		double decimal = 0.0;
		
		if (args.length > 0) {
			// If the decimal value is passed with the program arguments, take it
			try {
				decimal = Double.parseDouble(args[0]);
			}
			catch (NumberFormatException exc) { }
		} // args.length > 0
		while (0 >= decimal || 1 <= decimal)
			decimal = ConsoleInput.readDouble("Please enter the decimal value" +
					" (0 < z < 1)", "The entered value could not be " +
					"converted to double.");
		
		return decimal;
	} // getDecimalValue
	
	/**
	 * This method provides an array of booleans as binary representation of the
	 * decimal value that is being passed as argument.
	 * @param the decimal value
	 * @return the binary representation as array of booleans
	 */
	private static boolean[] toBinary(double decimal) {
		boolean[] toBinary = new boolean[52]; // maximum 52 positions
		for (int i = 0; i < 52; i++) {
			decimal *= 2;
			toBinary[i] = (decimal >= 1);
			if (toBinary[i])
				decimal--;
			if (decimal == 0.0)
				break;
		}
		
		return toBinary;
	}
	
	/**
	 * This method provides the decimal value of the passed array, that is
	 * assumed as binary representation of a decimal.
	 * @param the array of boolean as binary representation of the decimal
	 * @return the decimal value
	 */
	private static double fromBinary(boolean[] binary) {
		double decimal = 0.0;
		
		for (int i = 0; i < 52; )
			decimal += (binary[i++] ? 1 : 0) * (1/(Math.pow(2, i)));
		return decimal;
	}

}
